package com.jh.user.util;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.google.common.collect.ImmutableMap;
import org.inferred.freebuilder.FreeBuilder;
import org.jetbrains.annotations.Nullable;

import java.io.Serializable;
import java.util.Map;
import java.util.Objects;


/**
 * 用于接口响应的实体模型。
 * 当被用作接口（Feign）调用时，反序化时，{@code data} 属性会被映射为 {@code Map}（原始为JavaBean时）。
 *
 * @author Fuchun
 * @since 1.0
 */
@FreeBuilder
@JsonDeserialize(builder = RetEntity.Builder.class)
public abstract class RetEntity implements Serializable {

    static final String SUCCESS_CODE = "000000";
    static final String FAILURE_CODE = "999999";
    static final String UNKNOWN_CODE = "222222";
    static final String PROCESSING_CODE = "111111";

    public static RetEntity ok(@Nullable Object data) {
        return success(null, data);
    }

    public static RetEntity success(@Nullable String message) {
        return success(message, null);
    }

    public static RetEntity success(@Nullable String message, @Nullable Object data) {
        return new Builder()
                .setCode(SUCCESS_CODE)
                .setMessage(message)
                .setData(data).build();
    }

    public static RetEntity fail(@Nullable String message) {
        return fail(message, null);
    }

    /**
     * 执行失败（参数、业务等发生错误）。
     *
     * @param message 响应的提示消息。
     * @param data 响应的数据。
     */
    public static RetEntity fail(@Nullable String message, @Nullable Object data) {
        return new Builder()
                .setCode(FAILURE_CODE)
                .setMessage(message)
                .setData(data).build();
    }

    /**
     * 未知错误（服务器发生异常）。
     *
     * @param message 响应的提示消息。
     */
    public static RetEntity unknown(@Nullable String message) {
        return new Builder()
                .setCode(UNKNOWN_CODE).setMessage(message).build();
    }

    /**
     * 正在处理中（一般是异步调用接口返回）。
     *
     * @param message 响应的提示消息。
     */
    public static RetEntity processing(@Nullable String message) {
        return new Builder()
                .setCode(PROCESSING_CODE).setMessage(message).build();
    }

    /**
     * 返回码。
     */
    public abstract String getCode();

    /**
     * 返回的消息。
     */
    @Nullable
    public abstract String getMessage();

    /**
     * 返回的数据。
     */
    @Nullable
    public abstract Object getData();

    public Map<String, Object> toOldResult() {
        ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
        builder.put("resp_code", getCode());
        String message = getMessage();
        Object data = getData();
        if (message != null)
            builder.put("resp_message", message);
        if (data != null) {
            builder.put("result", data);
        }
        return builder.build();
    }

    public boolean isSuccess() {
        return Objects.equals(getCode(), SUCCESS_CODE);
    }

    public static class Builder extends RetEntity_Builder {}
}
